/***************************************************************************
 *   Copyleft 2006-2007 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#include "./Cursor3D.h"

/**************************************************************
* Constructors                                                *
***************************************************************/
Cursor3D::Cursor3D(): Object3D(6, 3) {
	Update(Point4D());

	mEdgeTable[0].mBegin = 0;
	mEdgeTable[0].mEnd = 1;

	mEdgeTable[1].mBegin = 2;
	mEdgeTable[1].mEnd = 3;

	mEdgeTable[2].mBegin = 4;
	mEdgeTable[2].mEnd = 5;

	mColor = RGB(0, 255, 255);
	mScreenPosition = Point4D(0.0f, 0.0f, 0.0f);
	mWorldPosition = Point4D(0.0f, 0.0f, 0.0f);
}
    
/**************************************************************
* Operators                                                   *
***************************************************************/


/**************************************************************
* Other helpful functions                                     *
***************************************************************/
/*virtual*/ cChar* Cursor3D::GetName() {
	return "Cursor3D";
}

/*virtual*/ cVoid Cursor3D::DisplayInfo(Renderer& renderer) {
	cChar buf[MAX_BUF_SIZE];
	cInt line = 4;
	cInt iHeight = renderer.GetHeight();

	sprintf_s(buf, "[%.2f, %.2f, %.2f]", mWorldPosition.mX,  mWorldPosition.mY,  mWorldPosition.mZ);
	renderer.DrawString(H_TXT_SPACER, iHeight - line++ * V_TXT_SPACER, buf, false, true, false);
	renderer.DrawString(H_TXT_SPACER, iHeight - line++ * V_TXT_SPACER, "World Position:", true, true, false);
	line++;
	sprintf_s(buf, "[%.0f, %.0f]", mScreenPosition.mX, mScreenPosition.mY);
	renderer.DrawString(H_TXT_SPACER, iHeight - line++ * V_TXT_SPACER, buf, false, true, false);
	renderer.DrawString(H_TXT_SPACER, iHeight - line++ * V_TXT_SPACER, "Screen Position:", true, true, false);
}

cVoid Cursor3D::Transform(Matrix4D& worldMatrix) {
	
}

cVoid Cursor3D::SetWorldPosition(const Point4D& point, Matrix4D& worldMatrix,
								 Matrix4D& persMatrix, cBool bChangeZ) {
	Matrix4D invWorld = worldMatrix.Invert();
	cFloat w;
	if (!bChangeZ) {
		mScreenPosition = point;
		mScreenPosition.mZ = (worldMatrix * mWorldPosition).mZ;
		w = persMatrix(4, 3) * mScreenPosition.mZ + 1.0f;
	} else {
		mScreenPosition = worldMatrix * mWorldPosition;
		w = 0.0416f * point.mX;
		mScreenPosition.mZ += w;
		w = persMatrix(4, 3) * w + 1.0f;
	}
	
	mScreenPosition.mX *= w;
	mScreenPosition.mY *= w;

	mWorldPosition = invWorld * mScreenPosition;
	Update(mWorldPosition);
}

cVoid Cursor3D::SetWorldPosition(Point4D& point, Matrix4D& worldMatrix) {
	mWorldPosition = point;
	mScreenPosition = worldMatrix * point;
	Update(mWorldPosition);
}

cVoid Cursor3D::Update(Point4D point) {
	mVertexTable[0] = Point4D(point.mX + CURSOR_SIZE, point.mY, point.mZ);
	mVertexTable[1] = Point4D(point.mX - CURSOR_SIZE, point.mY, point.mZ);
	mVertexTable[2] = Point4D(point.mX, point.mY + CURSOR_SIZE, point.mZ);
	mVertexTable[3] = Point4D(point.mX, point.mY - CURSOR_SIZE, point.mZ);
	mVertexTable[4] = Point4D(point.mX, point.mY, point.mZ + CURSOR_SIZE);
	mVertexTable[5] = Point4D(point.mX, point.mY, point.mZ - CURSOR_SIZE);
}

cVoid Cursor3D::Render(Renderer& renderer, Matrix4D& matrix, ProjectionPlane& plane) {
	Point4D a, b;
	
	if (mVisible) {
		if (mVertexTable && mEdgeTable) {
			for (cInt i = 0; i < mNrOfEdges; i++) {
				a = mVertexTable[mEdgeTable[i].mBegin];
				b = mVertexTable[mEdgeTable[i].mEnd];
				a = matrix * mMatrix * mObjectMatrix * a;
				b = matrix * mMatrix * mObjectMatrix * b;
				if (!Clip(a, b, plane)) {
					continue;
				}
				a.Normalize();
				b.Normalize();
				a.mX += (renderer.GetWidth() >> 1);
				a.mY = -a.mY + (renderer.GetHeight() >> 1);
				b.mX += (renderer.GetWidth() >> 1);
				b.mY = -b.mY + (renderer.GetHeight() >> 1);
				if (i == 0) {
					mColor = RGB(255, 0, 0);
				} else if (i == 1) {
					mColor = RGB(0, 255, 0);
				} else {
					mColor = RGB(0, 0, 255);
				}

				renderer.DrawLine(a, b, mColor);
			}
		}
	}
}

Point4D Cursor3D::GetWorldPosition() {
	return mWorldPosition;
}